package com.zhongli.devplatform.config;

import com.zhongli.devplatform.security.*;
import com.zhongli.devplatform.security.filter.JwtAuthenticationTokenFilter;
import com.zhongli.devplatform.security.qq.QQAuthenticationManager;
import com.zhongli.devplatform.security.handler.AuthenticationAccessDeniedHandler;
import com.zhongli.devplatform.security.handler.MyAuthenticationFailureHandler;
import com.zhongli.devplatform.security.handler.MyAuthenticationSuccessHandler;
import com.zhongli.devplatform.security.handler.MyLogoutHandler;
import com.zhongli.devplatform.security.qq.QQAuthenticationProcessingFilter;
import com.zhongli.devplatform.security.qq.QQAuthenticationProvider;
import com.zhongli.devplatform.security.weixin.WeixinAuthenticationFailureHandler;
import com.zhongli.devplatform.security.weixin.WeixinAuthenticationProcessingFilter;
import com.zhongli.devplatform.security.weixin.WeixinAuthenticationProvider;
import com.zhongli.devplatform.security.weixin.WeixinAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthenticationTokenFilter jwtRequestFilter;


    @Override
    public void configure(HttpSecurity http) throws Exception {

        // App没用跨域问题所以关闭csrf防护
        http.cors().and().csrf().disable()
                // 指定特殊需要放行的url
                .authorizeRequests().antMatchers("/authenticate","/user/register",
                "/user/forgetPwd","/v2/api-docs", "/configuration/ui",
                "/user/resetPwd","/user/getCode",
                "/swagger-resources", "/configuration/security",
                "/swagger-ui.html", "/webjars/**",
                "/swagger-resources/configuration/ui","/swagger-ui.html","doc.html","/favicon.ico")
                .permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                // 授权不需要登录权限的URL
                .antMatchers(
                        "/swagger-ui.html")
                .permitAll().
                // 所有请求必须验证
                anyRequest().authenticated().and().
                // make sure we use stateless session; session won't be used to
                // 配置自定义异常处理器
                //未经过认证
                exceptionHandling()
                .authenticationEntryPoint(new JwtAuthenticationEntryPoint())
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                //无权限
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler());

        // 在 UsernamePasswordAuthenticationFilter 前添加 QQAuthenticationFilter
        //http.addFilterAt(qqAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        //微信过滤器
        //http.addFilterAt(weixinAuthenticationProcessingFilter(),UsernamePasswordAuthenticationFilter.class);

        // 自定义认证过滤器
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);


        http.authorizeRequests()
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O o) {
                        o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource());
                        o.setAccessDecisionManager(accessDecisionManager());
                        return o;
                    }
                });
    }

    @Bean
    public QQAuthenticationProvider qqAuthenticationProvider(){
        return new QQAuthenticationProvider();
    }

    @Bean
    public WeixinAuthenticationProvider weixinAuthenticationProvider() {

        return new WeixinAuthenticationProvider();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
        auth.authenticationProvider(qqAuthenticationProvider());
        //auth.authenticationProvider(weixinAuthenticationProvider());
    }


    /**
     * 自定义 QQ登录认证过滤器
     */
    @Bean
    public QQAuthenticationProcessingFilter qqAuthenticationFilter(){
        QQAuthenticationProcessingFilter authenticationFilter = new QQAuthenticationProcessingFilter("/login/qq");
        SimpleUrlAuthenticationSuccessHandler simpleUrlAuthenticationSuccessHandler = new SimpleUrlAuthenticationSuccessHandler();
        simpleUrlAuthenticationSuccessHandler.setAlwaysUseDefaultTargetUrl(true);
        simpleUrlAuthenticationSuccessHandler.setDefaultTargetUrl("/user");
        authenticationFilter.setAuthenticationSuccessHandler(simpleUrlAuthenticationSuccessHandler);
        authenticationFilter.setAuthenticationManager(new QQAuthenticationManager());
        return authenticationFilter;
    }

    /**
     * 自定义 微信登录认证过滤器
     * @return
     */
    public WeixinAuthenticationProcessingFilter weixinAuthenticationProcessingFilter() throws Exception {

        WeixinAuthenticationProcessingFilter weixinAuthenticationProcessingFilter = new WeixinAuthenticationProcessingFilter();

        weixinAuthenticationProcessingFilter.setAuthenticationManager(authenticationManagerBean());
        weixinAuthenticationProcessingFilter.setAuthenticationSuccessHandler(new WeixinAuthenticationSuccessHandler());
        weixinAuthenticationProcessingFilter.setAuthenticationFailureHandler(new WeixinAuthenticationFailureHandler());
        return weixinAuthenticationProcessingFilter;


    }

    @Override
    public void setContentNegotationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
        super.setContentNegotationStrategy(contentNegotiationStrategy);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }


    @Bean
    public AccessDecisionManager accessDecisionManager() {
        return new UrlAccessDecisionManager();
    }

    @Bean
    public FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource() {
        return new UrlFilterInvocationSecurityMetadataSource();
    }


    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return new AuthenticationAccessDeniedHandler();
    }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new MyAuthenticationFailureHandler();
    }


    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new MyAuthenticationSuccessHandler();
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return new MyAuthenticationEntryPoint();
    }

    @Bean
    public LogoutHandler logoutHandler() {
        return new MyLogoutHandler();
    }


    @Configuration
    public class CorsConfig extends WebMvcConfigurerAdapter {
        private CorsConfiguration buildConfig() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            corsConfiguration.addAllowedHeader("*");
            corsConfiguration.addAllowedMethod("*");
            corsConfiguration.addExposedHeader("Authorization");
            return corsConfiguration;
        }

        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", buildConfig());
            return new CorsFilter(source);
        }

        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("*")
                    .allowCredentials(true)
                    .allowedMethods("GET", "POST", "DELETE", "PUT")
                    .maxAge(3600);
        }


//        @Bean
//    public WebMvcConfigurer corsConfigurer() {
//        return new WebMvcConfigurerAdapter() {
//            @Override
//            public void addCorsMappings(CorsRegistry registry) {
//                registry.addMapping("/**")
//                        .allowedOrigins("*")
//                        .allowedMethods("PUT", "DELETE", "GET", "POST", "OPTIONS")
//                        .allowedHeaders("*")
//                        .exposedHeaders("access-control-allow-headers",
//                                "access-control-allow-methods",
//                                "access-control-allow-origin",
//                                "access-control-max-age",
//                                "X-Frame-Options")
//                        .allowCredentials(true).maxAge(3600);
//            }
//        };
//
//    }

    }
}
